#ifndef M_FMT_H__
#define M_FMT_H__

#include "utils.hpp"
#include "message.hpp"
#include "levels.hpp"
#include <memory>
#include <vector>
#include <tuple>
#include <cassert>


namespace tclog{
    class FormatItem{
        public:
            using ptr=std::shared_ptr<FormatItem>;
            virtual ~FormatItem(){}
            virtual void format(std::ostream& os,const LogMsg& msg)=0;
    };

    class MsgFormatItem:public FormatItem{
        public:
            MsgFormatItem(const std::string &str=""){}
            virtual void format(std::ostream& os,const LogMsg& msg){
                os<<msg._payload;
            }
    };

    class LevelFormatItem : public FormatItem {
        public:
            LevelFormatItem(const std::string &str = ""){}
            virtual void format(std::ostream &os, const LogMsg &msg) {
                os << LogLevel::toString(msg._level);
            }
    };
    class LoggerFormatItem:public FormatItem{
        public:
            LoggerFormatItem(const std::string &str=""){}
            virtual void format(std::ostream& os,const LogMsg& msg){
                os<<msg._logger;
            }
    };
    class ThreadFormatItem : public FormatItem {
        public:
            ThreadFormatItem(const std::string &str = ""){}
            virtual void format(std::ostream &os, const LogMsg &msg) {
                os << msg._tid;
        }
    };
    class CFileFormatItem : public FormatItem {
    public:
        CFileFormatItem(const std::string &str = ""){}
        virtual void format(std::ostream &os, const LogMsg &msg) {
            os << msg._file;
        }
    };
    class CLineFormatItem : public FormatItem {
        public:
            CLineFormatItem(const std::string &str = ""){}
            virtual void format(std::ostream &os, const LogMsg &msg) {
                os << msg._line;
        }
    };
    class NLineFormatItem : public FormatItem {
        public:
            NLineFormatItem(const std::string &str = ""){}
            virtual void format(std::ostream &os, const LogMsg &msg) {
                os << "\n";
        }
    };
    class TabFormatItem : public FormatItem {
        public:
            TabFormatItem(const std::string &str = ""){}
            virtual void format(std::ostream &os, const LogMsg &msg) {
                os <<"\t";
        }
    };
    class TimeFormatItem:public FormatItem{
        private:
            std::string _format;
        public:
            TimeFormatItem(const std::string &format="%H:%M:%S"):_format(format){
                if(format.empty()) _format="%H:%M:%S";
            }

            virtual void format(std::ostream &os, const LogMsg &msg) {
                time_t t=msg._ctime;
                struct tm lt;
                localtime_r(&t,&lt);
                char tmp[128];
                strftime(tmp,127,_format.c_str(),&lt);
                os<<tmp;
        }
    };

    class OtherFormatItem : public FormatItem {
        private:
            std::string _str;
        public:
            OtherFormatItem(const std::string &str = ""):_str(str){}
            virtual void format(std::ostream &os, const LogMsg &msg) {
                os << _str;
        }
    };


    class Formatter{
        public:
            using ptr = std::shared_ptr<Formatter>;
            Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n"):
            _pattern(pattern){
            assert(parsePattern());
        }
        const std::string pattern() { return _pattern; } 

        std::string format(const LogMsg &msg) { 
            std::stringstream ss;
            format(ss,msg);
            return ss.str();
        }

        std::ostream& format(std::ostream &os, const LogMsg &msg) {
            for (auto &it : _items) {
                it->format(os, msg);
            }
            return os;
        }
        
        private:
        //根据不同的格式化字符创建不同的格式化子项对象
        FormatItem::ptr createItem(const std::string &key, const std::string &val) {
            /*
            %d 日期
            %T 缩进
            %t 线程id
            %p 日志级别
            %c 日志器名称
            %f 文件名
            %l 行号
            %m 日志消息[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n
            %n 换行
        */
            if(key=="d") return std::make_shared<TimeFormatItem>(val);
            if(key=="t") return std::make_shared<ThreadFormatItem>();
            if(key=="p") return std::make_shared<LevelFormatItem>();
            if(key=="c") return std::make_shared<LoggerFormatItem>();
            if(key=="f") return std::make_shared<CFileFormatItem>();
            if(key=="l") return std::make_shared<CLineFormatItem>();
            if(key=="m") return std::make_shared<MsgFormatItem>();
            if(key=="n") return std::make_shared<NLineFormatItem>();
            if(key=="T") return std::make_shared<TabFormatItem>();
            if(key.empty()) return std::make_shared<OtherFormatItem>(val);
            std::cout<<"unknown format item %"<<key<<std::endl;
            abort();
            return FormatItem::ptr();
        }
        
        bool parsePattern(){
            //解析日志格式字符串，生成对应的FormatItem对象
            //%d{%Y-%m-%d %H:%M:%S}  %p  %c  %f:%l  %m%n
            //解析成 TimeFormatItem LevelFormatItem LoggerFormatItem CFileFormatItem CLineFormatItem MsgFormatItem NLineFormatItem
            //存放在_items中
            std::vector<std::pair<std::string,std::string>> vec;
            size_t pos=0;
            std::string key,val;
            while(pos<_pattern.size()){
                //1.判断是否为%，不是就是原始字符
                
                if(_pattern[pos]!='%'){
                    val.push_back(_pattern[pos++]); 
                    continue;
                }
                //2.如果是%则判断下一个字符是否是%
                if(pos+1<_pattern.size()&&_pattern[pos+1]=='%'){
                    val.push_back('%');
                    pos+=2;
                    continue;
                }
                //3.如果不是%，则解析格式化字符串
                //%d %p %c %f %l %m %n %{xxxx}
                //先将原始字符串赋值
                if(!val.empty()){
                    vec.push_back(std::make_pair("",val));
                    val.clear();
                }
                pos+=1;
                if(pos==_pattern.size()) {
                    std::cout<<"pattern error"<<std::endl;
                    return false;
                }
                key=_pattern[pos];
                pos+=1;
                //4.判断是否有{xxxx}，有则解析
                if(pos<_pattern.size()&&_pattern[pos]=='{'){
                    pos+=1;
                    while(pos<_pattern.size()&&_pattern[pos]!='}'){
                        val.push_back(_pattern[pos++]);
                    }
                    if(pos==_pattern.size()) 
                    {
                        std::cout<<"{} not found"<<std::endl;
                        return false;
                    }
                    pos+=1;
                }
                vec.push_back(std::make_pair(key,val));
                key.clear();
                val.clear();
                
            }
            //5.根据解析得到的数据初始化_items
            for(auto& i:vec){
                _items.push_back(createItem(i.first,i.second));
            }
            return true;
        }

        private:
            std::string _pattern;
            std::vector<FormatItem::ptr> _items;
    };
    
}
#endif